package org.dromara.iot.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.ratelimiter.annotation.RateLimiter;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.web.core.BaseController;
import org.dromara.iot.domain.DeviceEvent;
import org.dromara.iot.domain.bo.IotElevatorEventBo;
import org.dromara.iot.domain.vo.IotElevatorVo;
import org.dromara.iot.enums.DeviceElevatorEventTypeEnum;
import org.dromara.iot.service.IIotElevatorEventService;
import org.dromara.iot.service.IIotElevatorService;
import org.dromara.system.domain.vo.SysOssUploadVo;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.ISysOssService;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.*;

@Slf4j
@SaIgnore
@RequiredArgsConstructor
@RestController
@RequestMapping
public class CameraEventController extends BaseController {
    private final ISysOssService ossService;
    private final IIotElevatorEventService iotElevatorEventService;
    private final IIotElevatorService iotElevatorService;
    //默认保存时间
    private final Integer saveDays = 60;

    // 线程池配置 - 根据CPU核心数动态设置
    private static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors();
    private static final int MAX_POOL_SIZE = CORE_POOL_SIZE * 2;
    private static final ExecutorService executor = new ThreadPoolExecutor(
            CORE_POOL_SIZE,
            MAX_POOL_SIZE,
            60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(5000),
            new ThreadPoolExecutor.CallerRunsPolicy());

    // 请求速率控制 - 每秒最大请求数
    @RateLimiter(key = "#event", count = 1000)
    @PostMapping("/event")
    public void export(@RequestBody JSONObject deviceEvent) {
        executor.execute(() -> {
            try {
                processEvent(deviceEvent);
            } catch (Exception e) {
                log.error("处理事件异常", e);
            }
        });
    }

    private void processEvent(JSONObject deviceEvent) {
        DeviceEvent event = JSONUtil.toBean(deviceEvent, DeviceEvent.class);
        IotElevatorVo iotElevatorVo = iotElevatorService.selectByIdentifyCode(event.getDevid());
        if (iotElevatorVo == null) {
            log.info("上报的图片未找到电梯:{}", event.getDevid());
            return;
        }
        RedisUtils.setCacheObject(GlobalConstants.CAMERA_KEY + event.getDevid() + ":" + event.getEvent().getCode(), JSONUtil.toJsonStr(event));
        log.info("接收到摄像头上送的事件:{}", deviceEvent);
        if (event.getEvent().getCode() == DeviceElevatorEventTypeEnum.TIMED_REPORT.getCode()) {
            IotElevatorEventBo iotElevatorEvent = event.toIotElevatorEvent();
            iotElevatorEvent.setElevatorId(iotElevatorVo.getElevatorId());
            iotElevatorEvent.setElevatorName(iotElevatorVo.getElevatorName());
            iotElevatorEvent.setUseUnit(iotElevatorVo.getUseUnit());
            iotElevatorEvent.setServerUnit(iotElevatorVo.getMaintenanceUnit());
            iotElevatorEvent.setRemark(iotElevatorVo.getElevatorName() + ":" + event.getEvent().getDescription());
            iotElevatorEventService.insertByBo(iotElevatorEvent, false);
        }
    }

    @RateLimiter(key = "#picture")
    @PostMapping(value = "/picture", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public void picture(
            @RequestParam("devid") String devid,
            @RequestParam("nonce") String nonce,
            @RequestParam("timestamp") Long timestamp,
            @RequestParam("sign") String sign,
            @RequestParam("eventTime") Long eventTime,
            @RequestPart("file") MultipartFile file) throws IOException {
        String originalFilename = file.getOriginalFilename();
        File tempFile = FileUtils.touch(originalFilename);
        FileUtils.writeBytes(file.getBytes(), tempFile);
        executor.execute(() -> {
            try {
                processPicture(devid, tempFile);
            } catch (Exception e) {
                log.error("处理图片异常", e);
            }
        });
    }

    private void processPicture(String devid, File file) {
        IotElevatorVo iotElevatorVo = iotElevatorService.selectByIdentifyCode(devid);
        if (iotElevatorVo == null) {
            log.info("上报的图片未找到电梯:{}", devid);
            return;
        }
        SysOssVo oss = ossService.upload(file);
        SysOssUploadVo uploadVo = new SysOssUploadVo();
        uploadVo.setUrl(oss.getUrl());
        uploadVo.setFileName(oss.getOriginalName());
        uploadVo.setOssId(oss.getOssId().toString());
        log.info("接收上报的图片: devid={}, file={}", devid, file.getName());
        
        String originalFilename = file.getName();
        String[] split = originalFilename.split("_");
        String event = RedisUtils.getCacheObject(GlobalConstants.CAMERA_KEY + devid + ":" + split[split.length - 1].split("\\.")[0]);
        if (event == null) {
            log.info("上报的图片未找到事件:{}", devid);
            return;
        }

        DeviceEvent deviceEvent = JSONUtil.toBean(event, DeviceEvent.class);
        log.info("告警事件:{}", JsonUtils.toJsonString(deviceEvent));

        IotElevatorEventBo iotElevatorEvent = deviceEvent.toIotElevatorEvent();
        iotElevatorEvent.setOssId(Long.parseLong(uploadVo.getOssId()));
        iotElevatorEvent.setElevatorId(iotElevatorVo.getElevatorId());
        iotElevatorEvent.setElevatorName(iotElevatorVo.getElevatorName());
        iotElevatorEvent.setUseUnit(iotElevatorVo.getUseUnit());
        iotElevatorEvent.setServerUnit(iotElevatorVo.getMaintenanceUnit());

        JSONObject obj = JSONUtil.createObj();
        obj.set("type", "tiringEvent");
        obj.set("eventTime", iotElevatorEvent.getReportTime());
        obj.set("data", iotElevatorVo.getElevatorName() + ":" + deviceEvent.getEvent().getDescription());
        obj.set("elevatorId", String.valueOf(iotElevatorVo.getElevatorId()));
        iotElevatorEvent.setRemark(obj.toString());
        iotElevatorEventService.insertByBo(iotElevatorEvent, true);
    }

    /**
     * 每天凌晨去删除事件信息
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void deleteEvent() {
        iotElevatorEventService.deleteByReportTime(saveDays);
    }

}
